package com.enlorenz.common.security.des;

import com.enlorenz.common.security.Coder4Base;
import com.enlorenz.common.util.CodeUtils;
import com.enlorenz.common.util.CommonContants;
import com.enlorenz.common.util.StringUtils;

/**
 * DES-Data Encryption Standard,即数据加密算法。是IBM公司于1975年研究成功并公开发表的。
 * DES算法的入口参数有三个:Key、Data、Mode。其中Key为8个字节共64位,是DES算法的工作密钥;
 * Data也为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密。 
　　DES算法把64位的明文输入块变为64位的密文输出块,它所使用的密钥也是64位。 
 * @author Karma
 */
public abstract class AbstractDes {
	public static final String CHAR_SET=CommonContants.UTF_8_CHARSET;
	 /** 
     * ALGORITHM 算法 <br> 
     * 可替换为以下任意一种算法，同时key值的size相应改变。 
     * <pre> 
     * DES                  key size must be equal to 56 
     * DESede(TripleDES)    key size must be equal to 112 or 168 
     * AES                  key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available 
     * Blowfish             key size must be multiple of 8, and can only range from 32 to 448 (inclusive) 
     * RC2                  key size must be between 40 and 1024 bits 
     * RC4(ARCFOUR)         key size must be between 40 and 1024 bits 
     * </pre> 
     *  
     * 在Key toKey(byte[] key)方法中使用下述代码 
     * <code>SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);</code> 替换 
     * <code> 
     * DESKeySpec dks = new DESKeySpec(key); 
     * SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM); 
     * SecretKey secretKey = keyFactory.generateSecret(dks); 
     * </code> 
     */   
    public static enum DesTypeEnum {
    	DES,DESede,DESDouble,AES,Blowfish,RC2,RC4
    }
    //数据编码类型
    public static enum EncodeTypeEnum{
    	ASCII,HEX,BASE64
    }
    //编码
    private String encoding=CHAR_SET;
    private EncodeTypeEnum dataType=EncodeTypeEnum.ASCII;
    private EncodeTypeEnum keyType=EncodeTypeEnum.HEX;
    private EncodeTypeEnum securityType=EncodeTypeEnum.HEX;
    
    
    public String getEncoding() {
		return encoding;
	}
    /**
     * 设置编码
     * @param encoding
     */
	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}

	/**
	 * 设置加密后数据类型
	 * @param dataType
	 */
	public void setSecurityType(EncodeTypeEnum securityType) {
		this.securityType = securityType;
	}
	
	/**
	 * 设置明文数据类型
	 * @param dataType
	 */
	public void setDataType(EncodeTypeEnum dataType) {
		this.dataType = dataType;
	}

	/**
	 * 设置密钥类型
	 * @param keyType
	 */
	public void setKeyType(EncodeTypeEnum keyType) {
		this.keyType = keyType;
	}


	/** 
     * 加密 
     * @param data 数据
     * @param key 密钥
     * @return 加密后数据
     * @throws Exception 
     */  
    public byte[] encrypt(byte[] data, byte [] key) {  
    	return BaseDesUtils.encrypt(data,key,getDesTypeEnum(),getDesNameEnum()); 
    }  
    

    /** 
     * 解密 
     * @param data 数据
     * @param key 密钥
     * @return 解密后数据
     * @throws Exception 
     */  
    public byte[] decrypt(byte[] data, byte [] key) {  
    	return BaseDesUtils.decrypt(data,key,getDesTypeEnum(),getDesNameEnum()); 
    } 
    
    protected abstract String getDesTypeEnum();
    
    /**
     * 获取DES的名称
     * @return
     */
    protected String getDesNameEnum(){
    	return getDesTypeEnum();
    }

    
    /** 
     * 加密 
     * @param data 数据
     * @param key 密钥
     * @return 加密后数据
     * @throws Exception 
     */  
    public String encrypt(String data, String key) {  
    	byte[] result=encrypt(string2Bytes(data,dataType)
    			,string2Bytes(key,keyType)); 
    	return bytes2String(result,securityType);
    }
    

    
    /** 
     * 解密 
     * @param data 数据
     * @param key 密钥
     * @return 解密后数据
     * @throws Exception 
     */  
    public String decrypt(String data, String key) {  
    	byte [] result=decrypt(string2Bytes(data,securityType),
    			string2Bytes(key,keyType)); 
    	return bytes2String(result,dataType);
    } 
	
    
    protected String bytes2String(byte [] data,EncodeTypeEnum dataType){
    	if(dataType.equals(EncodeTypeEnum.ASCII)){
    		return StringUtils.newString(data,encoding);
    	}else if(dataType.equals(EncodeTypeEnum.HEX)){
    		return CodeUtils.bytes2HexString(data);
    	}else if(dataType.equals(EncodeTypeEnum.BASE64)){
    		return Coder4Base.encryptBase64(data);
    	}else{
    		return null;
    	}
    }
    
    protected byte [] string2Bytes(String data,EncodeTypeEnum dataType){
    	if(dataType.equals(EncodeTypeEnum.ASCII)){
    		return StringUtils.getBytes(data,encoding);
    	}else if(dataType.equals(EncodeTypeEnum.HEX)){
    		return CodeUtils.hexString2Bytes(data);
    	}else if(dataType.equals(EncodeTypeEnum.BASE64)){
    		return Coder4Base.decryptBASE64(data);
    	}else{
    		return null;
    	}
    }
    
    /** 
     * 生成密钥 
     * @return 密钥 
     * @throws Exception 
     */  
    public String initKey(){  
    	byte [] buff=BaseDesUtils.initKey(null, getDesNameEnum());
        return bytes2String(buff,keyType);  
    }  
    
    public EncodeTypeEnum getDataType() {
		return dataType;
	}

	public EncodeTypeEnum getKeyType() {
		return keyType;
	}

	public EncodeTypeEnum getSecurityType() {
		return securityType;
	}
}
